package cn.edu.sgu.www.mhxysy.function.computer.attribute.impl;

import cn.edu.sgu.www.mhxysy.entity.equipment.Equipment;
import cn.edu.sgu.www.mhxysy.entity.except.AttributePoint;
import cn.edu.sgu.www.mhxysy.entity.except.JiadianProperty;
import cn.edu.sgu.www.mhxysy.entity.except.Property;
import cn.edu.sgu.www.mhxysy.entity.gang.GangSkill;
import cn.edu.sgu.www.mhxysy.entity.gang.GangSkillCategory;
import cn.edu.sgu.www.mhxysy.entity.qiling.Qiling;
import cn.edu.sgu.www.mhxysy.entity.role.RoleAccount;
import cn.edu.sgu.www.mhxysy.entity.role.RoleJiadian;
import cn.edu.sgu.www.mhxysy.entity.role.RoleProperty;
import cn.edu.sgu.www.mhxysy.entity.xingyin.Xingyin;
import cn.edu.sgu.www.mhxysy.enums.InlayStatus;
import cn.edu.sgu.www.mhxysy.enums.OpenStatus;
import cn.edu.sgu.www.mhxysy.enums.WearStatus;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.function.computer.attribute.AttributeComputer;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.BaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentMapper;
import cn.edu.sgu.www.mhxysy.mapper.except.AttributePointMapper;
import cn.edu.sgu.www.mhxysy.mapper.except.JiadianPropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.except.PropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoMapper;
import cn.edu.sgu.www.mhxysy.mapper.gang.GangSkillCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.gang.GangSkillMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RoleAccountMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RoleJiadianMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RolePropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.school.SchoolSkillMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinMapper;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import cn.edu.sgu.www.mhxysy.vo.baoshi.BaoshiVO;
import cn.edu.sgu.www.mhxysy.vo.except.AttributeVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 角色属性计算器
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Component
public class RoleAttributeComputer implements AttributeComputer {

    List<RoleProperty> list;
    Map<String, Integer> attribute = new HashMap<>();

    private final FabaoMapper fabaoMapper;
    private final BaoshiMapper baoshiMapper;
    private final QilingMapper qilingMapper;
    private final XingyinMapper xingyinMapper;
    private final PropertyMapper propertyMapper;
    private final EquipmentMapper equipmentMapper;
    private final GangSkillMapper gangSkillMapper;
    private final RoleAccountMapper roleAccountMapper;
    private final RoleJiadianMapper roleJiadianMapper;
    private final SchoolSkillMapper schoolSkillMapper;
    private final RolePropertyMapper rolePropertyMapper;
    private final AttributePointMapper attributePointMapper;
    private final JiadianPropertyMapper jiadianPropertyMapper;
    private final QilingAttributeMapper qilingAttributeMapper;
    private final XingyinAttributeMapper xingyinAttributeMapper;
    private final GangSkillCategoryMapper gangSkillCategoryMapper;
    private final EquipmentAttributeMapper equipmentAttributeMapper;

    @Autowired
    public RoleAttributeComputer(
            FabaoMapper fabaoMapper,
            BaoshiMapper baoshiMapper,
            QilingMapper qilingMapper,
            XingyinMapper xingyinMapper,
            PropertyMapper propertyMapper,
            EquipmentMapper equipmentMapper,
            GangSkillMapper gangSkillMapper,
            RoleAccountMapper roleAccountMapper,
            RoleJiadianMapper roleJiadianMapper,
            SchoolSkillMapper schoolSkillMapper,
            RolePropertyMapper rolePropertyMapper,
            AttributePointMapper attributePointMapper,
            JiadianPropertyMapper jiadianPropertyMapper,
            QilingAttributeMapper qilingAttributeMapper,
            XingyinAttributeMapper xingyinAttributeMapper,
            GangSkillCategoryMapper gangSkillCategoryMapper,
            EquipmentAttributeMapper equipmentAttributeMapper) {
        this.fabaoMapper = fabaoMapper;
        this.baoshiMapper = baoshiMapper;
        this.qilingMapper = qilingMapper;
        this.xingyinMapper = xingyinMapper;
        this.propertyMapper = propertyMapper;
        this.equipmentMapper = equipmentMapper;
        this.gangSkillMapper = gangSkillMapper;
        this.roleAccountMapper = roleAccountMapper;
        this.roleJiadianMapper = roleJiadianMapper;
        this.schoolSkillMapper = schoolSkillMapper;
        this.rolePropertyMapper = rolePropertyMapper;
        this.attributePointMapper = attributePointMapper;
        this.jiadianPropertyMapper = jiadianPropertyMapper;
        this.qilingAttributeMapper = qilingAttributeMapper;
        this.xingyinAttributeMapper = xingyinAttributeMapper;
        this.gangSkillCategoryMapper = gangSkillCategoryMapper;
        this.equipmentAttributeMapper = equipmentAttributeMapper;
    }

    @SneakyThrows
    @Override
    public Map<String, Integer> apply(String roleId) {
        RoleAccount roleAccount = roleAccountMapper.selectById(roleId);

        if (roleAccount == null) {
            throw new GlobalException(ResponseCode.CONFLICT, "操作失败，角色不存在！");
        }

        // 查询全部角色属性类型
        list = rolePropertyMapper.selectList(null);

        /*
         * 计算角色属性
         * 影响角色属性的因素有：
         * 1、法宝：穿戴法宝会影响角色的：物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 2、经脉：激活经脉点会影响角色的：气血、魔法、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 3、装备：穿戴装备会影响角色的：气血、魔法、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 4、器灵：在穿戴的装备中镶嵌器灵会影响角色的：气血、魔法、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 5、宝石：在穿戴的装备中镶嵌宝石会影响角色的：气血、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 6、星印：穿戴星印会影响角色的：气血、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 7、门派技能：学习门派技能会影响角色的：气血、物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 8、加点（月饼、粽子、潜能果）：
         * 加点（月饼、粽子）会直接影响角色的：物理伤害、物理防御、法术伤害、法术防御、速度
         * 兑换潜能果（摆放不同的四时、天象、节气图案）会影响角色的：物理伤害、物理防御、法术伤害、法术防御、速度、治疗强度
         * 9、帮派技能：学习帮派技能会影响角色的：气血、魔法
         */
        for (RoleProperty roleProperty : list) {
            attribute.put(roleProperty.getName(), 0);
        }

        /*
         * 1、法宝
         */
        // 查询角色法宝增加的属性
        List<AttributeVO> properties = fabaoMapper.selectProperty(roleId);

        addProperty(properties);

        /*
         * 2、经脉
         */
        // todo

        /*
         * 3、装备
         */
        // 1、查询角色穿戴的装备
        Map<String, Object> columnMap = new HashMap<>();

        columnMap.put("role_id", roleId);
        columnMap.put("wear_status", WearStatus.YCD.getValue());

        List<Equipment> equipmentList = equipmentMapper.selectByMap(columnMap);

        if(CollectionUtils.isNotEmpty(equipmentList)) {
            for (Equipment equipment : equipmentList) {
                String equipmentId = equipment.getId();

                /*
                 * 3、装备
                 */
                properties = equipmentAttributeMapper.selectAttributes(equipmentId);

                addProperty(properties);

                /*
                 * 4、器灵
                 */
                QueryWrapper<Qiling> queryWrapper = new QueryWrapper<>();

                queryWrapper.eq("equipment_id", equipmentId);
                queryWrapper.eq("inlay_status", InlayStatus.YXQ.getValue());

                Qiling qiling = qilingMapper.selectOne(queryWrapper);

                if (qiling != null) {
                    properties = qilingAttributeMapper.selectAttributes(qiling.getId());

                    addProperty(properties);
                }

                /*
                 * 5、宝石
                 */
                // 装备宝石增加的属性
                List<BaoshiVO> attributes = baoshiMapper.selectAttributes(equipmentId);

                if (CollectionUtils.isNotEmpty(attributes)) {
                    for (BaoshiVO attribute : attributes) {
                        String propertyName = attribute.getPropertyName();
                        Integer propertyValue = attribute.getGrade() * attribute.getPropertyValue();

                        addProperty(propertyName, propertyValue);
                    }
                }
            }
        }

        /*
         * 6、星印
         */
        // 查询角色穿戴的星印
        columnMap.clear();
        columnMap.put("role_id", roleId);
        columnMap.put("wear_status", WearStatus.YCD.getValue());

        List<Xingyin> xingyins = xingyinMapper.selectByMap(columnMap);

        if (CollectionUtils.isNotEmpty(xingyins)) {
            for (Xingyin xingyin : xingyins) {
                properties = xingyinAttributeMapper.selectAttributes(xingyin.getId());

                addProperty(properties);
            }
        }

        /*
         * 7、门派技能
         */
        // 查询角色门派技能增加的属性
        properties = schoolSkillMapper.selectProperty(roleId);

        addProperty(properties);

        /*
         * 8、加点
         */
        // 查询角色开启的加点
        QueryWrapper<RoleJiadian> jiadianQueryWrapper = new QueryWrapper<>();

        jiadianQueryWrapper.eq("role_id", roleId);
        jiadianQueryWrapper.eq("open_status", OpenStatus.OPEN.getValue());

        RoleJiadian roleJiadian = roleJiadianMapper.selectOne(jiadianQueryWrapper);
        // 获取类对象
        Class<? extends RoleJiadian> jiadianClass = roleJiadian.getClass();

        // 查询所有加点属性
        List<JiadianProperty> jiadianProperties = jiadianPropertyMapper.selectList(null);

        for (JiadianProperty jiadianProperty : jiadianProperties) {
            Integer propertyId = jiadianProperty.getPropertyId();

            // 查询加点对应的属性点数值
            QueryWrapper<AttributePoint> pointQueryWrapper = new QueryWrapper<>();

            pointQueryWrapper.eq("point_id", propertyId);

            List<AttributePoint> attributePoints = attributePointMapper.selectList(pointQueryWrapper);

            for (AttributePoint attributePoint : attributePoints) {
                for (RoleProperty roleProperty : list) {
                    String name = roleProperty.getName();

                    if (attributePoint.getPropertyId().equals(roleProperty.getPropertyId())) {
                        BigDecimal propertyValue = attributePoint.getPropertyValue();

                        Field field = jiadianClass.getDeclaredField(jiadianProperty.getName());

                        field.setAccessible(true);

                        BigDecimal value = propertyValue.multiply(
                                BigDecimal.valueOf(
                                        (Integer) field.get(roleJiadian)
                                )
                        );

                        attribute.put(name, attribute.get(name) + value.intValue());

                        break;
                    }
                }
            }
        }

        /*
         * 9、帮派技能
         */
        // 查询角色的帮派技能
        columnMap.clear();
        columnMap.put("role_id", roleId);

        List<GangSkill> gangSkills = gangSkillMapper.selectByMap(columnMap);

        if (gangSkills.size() > 0) {
            for (GangSkill gangSkill : gangSkills) {
                Integer categoryId = gangSkill.getCategoryId();
                GangSkillCategory gangSkillCategory = gangSkillCategoryMapper.selectById(categoryId);

                Integer propertyId = gangSkillCategory.getPropertyId();

                if (propertyId != null) {
                    Property property = propertyMapper.selectById(propertyId);

                    BigDecimal propertyValue = gangSkillCategory.getPropertyValue();
                    String propertyName = property.getName();
                    Integer grade = gangSkill.getGrade();

                    if (gangSkillCategory.getNote().contains("比例")) { // 强壮按比例提升气血
                        for (RoleProperty roleProperty : list) {
                            String name = roleProperty.getName();
                            String note = roleProperty.getNote();

                            if (propertyName.equals(note)) {
                                Integer value = attribute.get(name);

                                // 属性值 × (1 + 百分比)
                                BigDecimal bigDecimal = BigDecimal.valueOf(value).multiply(
                                        BigDecimal.valueOf(1).add(propertyValue)
                                );

                                attribute.put(name, bigDecimal.intValue());

                                break;
                            }
                        }
                    } else {
                        BigDecimal multiply = BigDecimal.valueOf(grade).multiply(propertyValue);

                        addProperty(propertyName, multiply.intValue());
                    }
                }
            }
        }

        return attribute;
    }

    /**
     * 增加属性
     * @param properties 属性列表
     */
    private void addProperty(List<AttributeVO> properties) {
        if (CollectionUtils.isNotEmpty(properties)) {
            for (AttributeVO property : properties) {
                String propertyName = property.getPropertyName();
                Integer propertyValue = property.getPropertyValue();

                addProperty(propertyName, propertyValue);
            }
        }
    }

    /**
     * 增加属性
     * @param propertyName 属性名
     * @param propertyValue 属性值
     */
    private void addProperty(String propertyName, Integer propertyValue) {
        for (RoleProperty roleProperty : list) {
            String name = roleProperty.getName();
            String note = roleProperty.getNote();

            if (propertyName.equals(note)) {
                Integer value = attribute.get(name);

                attribute.put(name, value + propertyValue);

                break;
            }
        }
    }

}